#include <iostream>

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <cstring>
#include <unistd.h>
#include <cerrno>
using namespace std;

void Usage(const string &process)
{
    cout << "Usage: " << process << " server_ip server_ip" << endl;
}

//./udp_client server_ip server_port  向服务器发消息
int main(int argc, char **argv)
{
    if (argc != 3)
    {
        Usage(argv[0]);
        return 1;
    }

    string serverip = argv[1]; // 字符串的点分十进制
    uint16_t serverport = stoi(argv[2]);

    // 1. 创建套接字,创建文件信息
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        cerr << "socket error: " << strerror(errno) << endl;
        return 2;
    }
    cout << "create socket success: " << sock << endl;
    // 2. 绑定
    // 其中客户端的socket也要绑定，但是不需要显示bind（client会在首次发送数据的时候会自动进行bind）
    // 不推荐自己绑定，为什么？服务器的端口号一定是众所周知的，不可改变。而client 需要 port，让其随机bind端口
    // client一般不绑定一个确定的socket因为：client 会非常多（打开如何软件），可能会导致别人占了你的端口
    // 就导致无法启动


    // 2.1 填充server信息：
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    while (true)
    {
        string inbuffer;
        cout << "Please Enter# ";
        getline(cin, inbuffer);

        // 发给：
        int n = sendto(sock,inbuffer.c_str(),inbuffer.size(),0,(struct sockaddr*)&server,sizeof(server));
        if(n>0)//发送成功
        {
            char buffer[1024];
            //收消息
            struct sockaddr_in temp;
            socklen_t len = sizeof(temp);
            ssize_t m = recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);//虽然没用但也是要填的temp
            if(m > 0)
            {
                buffer[m] = 0;
                cout << "server echo# " << buffer << endl;
            }
            else 
                break;
        }
    }   

    close(sock); // 把文件描述符关掉
    return 0;
}